package com.k.kc.util;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Random;

/**
 * 可以生成各种加密算法的key
 * AES标准所要求的密钥大小应为128、192或256位，分别为16、24和32字节。
 *
 * @author kkk
 */
public class KeyGen {
    private static final char[] CHAR_ARRAY = {
            '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ,
            'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' ,
            'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' ,
            'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 'M' ,
            'N' , 'O' , 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z'
    };

    private static byte[] randomByteArray(int bitLength) {
        Random random = new Random();
        byte[] bytes = new byte[bitLength / 8];
        random.nextBytes(bytes);
        return bytes;
    }

    private static byte[] randomByteArrayUnsigned(int bitLength) {
        Random random = new Random();
        int byteLength = bitLength / 8;
        byte[] bytes = new byte[byteLength];
        for (int i = 0; i < byteLength; i++) {
            bytes[i] = (byte) random.nextInt(127);
        }
        return bytes;
    }

    /**
     * 生成 n 位 加密算法 key
     *
     * @param bit n位
     * @return byte array
     */
    public static byte[] keyByteArray(int bit) {
        //randomByteArray(bit);
        return randomByteArrayUnsigned(bit);
    }

    public static byte[] key128bitByteArray() {
        return keyByteArray(128);
    }

    public static byte[] key256bitByteArray() {
        return keyByteArray(256);
    }

    /**
     * 生成 n 位 加密算法 key
     *
     * @param b n 位
     * @return base64 string
     */
    public static String keyBase64(int b) {
        byte[] bytes = keyByteArray(b);
        return ByteUtils.toBase64(bytes);
    }

    /**
     * 生成 n 位 加密算法 key 夸语言使用的话,优先使用 byte[] key
     * @param b bit 位
     * @return string
     */
    public static String keyString(int b){
        if(b%8 != 0){
            throw new IllegalArgumentException("非法位数");
        }
        int n = b/8;
        StringBuilder keyStr = new StringBuilder();
        Random random = new Random();
        for(int i=0;i<n;i++){
            char charX = CHAR_ARRAY[random.nextInt(CHAR_ARRAY.length)];
            keyStr.append(charX);
        }
        return keyStr.toString();
    }

    /**
     * 生成 128 bit (16 Byte) key
     *
     * @return 128 bit key
     */
    public static String key128bitBase64() {
        return keyBase64(128);
    }

    /**
     * 生成 256 bit (32 Byte) key
     *
     * @return 256 bit key base64
     */
    public static String key256bitBase64() {
        return keyBase64(256);
    }

    /**
     * 生成 512 bit (32 Byte) key
     *
     * @return 256 bit key base64
     */
    public static String key512bitBase64() {
        return keyBase64(512);
    }

    public static void writeByteArrayToFile(byte[] b, String filePathname) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(filePathname);
            fos.write(b);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static byte[] readFileToByteArray(String filePathname) {
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        byte[] b = null;
        try {
            fis = new FileInputStream(filePathname);
            bos = new ByteArrayOutputStream();
            int i;
            while ((i = fis.read()) != -1) {
                bos.write(i);
            }
            b = bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return b;
    }

    // ==================================================================
    // KeyGen test
    // ==================================================================

    public static void main(String[] args) {
        /*
         [41, 55, 105, 35, 66, 5, 43, 0, 30, 68, 12, 87, 85, 94, 125, 60]
         128 bit key base64:KTdpI0IFKwAeRAxXVV59PA==
         [41, 55, 105, 35, 66, 5, 43, 0, 30, 68, 12, 87, 85, 94, 125, 60]
         */
        // 1.key
        byte[] key128 = key128bitByteArray();
        System.out.println("1.生成128位密钥：" + Arrays.toString(key128));

        // 2.1 key -> base64
        String key128Base64 = ByteUtils.toBase64(key128);
        System.out.println("2.将 密钥(byte array) 转为 base64:" + key128Base64);

        // 2.2. base64 ->key
        byte[] bb = ByteUtils.fromBase64(key128Base64, StandardCharsets.UTF_8);
        System.out.println("3.将 密钥(base64) 转为 byteArray：" + Arrays.toString(bb));

        // 3.1 key -> file
        String filePathname = "c:/test/key128.key";
        writeByteArrayToFile(key128, filePathname);
        System.out.println("4.将 密钥(byte array) 写进 文件:" + filePathname);

        // 3.2 file -> key
        byte[] keyFile = readFileToByteArray(filePathname);
        System.out.println("5.将 密钥(byte array) 读出从：" + filePathname + " data:" + Arrays.toString(keyFile));

//      // 4.1
        byte[] key128one = "1234567890123456".getBytes(StandardCharsets.UTF_8);
        System.out.println(key128one.length * 8);
    }
}
